package servlet;

import anno.RequestBody;
import anno.ResponseBody;
import anno.ioc.ServletInjector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import utils.JDBCUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

public class BaseServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        // 在Servlet初始化时注入依赖
        ServletInjector.inject(this);
    }
    protected static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        // 创建JavaTimeModule模块
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        // 为 LocalDateTime 添加序列化配置
        javaTimeModule.addSerializer(LocalDateTime.class, new ToStringSerializer(LocalDateTime.class));
        // 注册模块
        objectMapper.registerModule(javaTimeModule);
        // 配置 ObjectMapper 以格式化日期时间
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        // 忽略未知属性
        objectMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取操作参数，用于确定要调用的方法
        String operation = req.getParameter("operation");
        if (operation == null) {
            // 如果操作参数不存在，返回400错误
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing operation parameter.");
            return;
        }

        System.out.println("本次调用方法：" + operation);
        // 获取当前类中的所有方法
        Method[] methods = this.getClass().getDeclaredMethods();
        // 遍历方法
        for (Method method : methods) {
            // 找到名称与操作参数相同的方法
            if (method.getName().equals(operation)) {
                try {
                    // 设置方法为可访问状态
                    method.setAccessible(true);

                    // 获取方法参数
                    Parameter[] parameters = method.getParameters();
                    // 用于存储方法调用时的参数值
                    Object[] args = new Object[parameters.length];
                    // 获取请求中的查询参数
                    Map<String, String> queryParams = getQueryParams(req);

                    // 设置参数值
                    for (int i = 0; i < parameters.length; i++) {
                        Parameter parameter = parameters[i];
                        Class<?> parameterType = parameter.getType();
                        if (parameterType.equals(HttpServletRequest.class)) {
                            // 如果参数类型是 HttpServletRequest，设置为当前请求对象
                            args[i] = req;
                        } else if (parameterType.equals(HttpServletResponse.class)) {
                            // 如果参数类型是 HttpServletResponse，设置为当前响应对象
                            args[i] = resp;
                        } else if (parameter.isAnnotationPresent(RequestBody.class)) {
                            // 如果参数上有 @RequestBody 注解，从请求体读取并转换为相应类型
                            args[i] = readRequestBody(req, parameterType);
                        } else {
                            // 获取参数名称
                            String paramName = parameter.getName();
                            if (!"operation".equals(paramName)) {
                                // 如果参数不是 operation，从查询参数中获取并设置
                                String paramValue = queryParams.get(paramName);
                                args[i] = paramValue; // 默认为 String 类型
                            }
                        }
                    }

                    // 调用方法并获取返回值
                    Object returnValue = method.invoke(this, args);

                    // 如果方法有 @ResponseBody 注解，则将返回值作为 JSON 响应
                    if (method.isAnnotationPresent(ResponseBody.class) && returnValue != null) {
                        sendJsonResponse(resp, returnValue);
                    }
                } catch (Exception e) {
                    // 处理异常
                    handleException(e);
                }finally {
                    JDBCUtils.closeConnection();
                }
            }
        }
    }

    // 处理异常，打印根本原因的堆栈信息
    private void handleException(Exception e) {
        Throwable rootCause = findRootCause(e);
        if (rootCause != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            rootCause.printStackTrace(pw);
            String stackTrace = sw.toString();
            e.printStackTrace();
        }
    }

    // 递归查找根本原因
    private Throwable findRootCause(Throwable throwable) {
        Throwable rootCause = throwable;
        while (rootCause.getCause() != null) {
            rootCause = rootCause.getCause();
        }
        return rootCause;
    }

    // 发送JSON响应
    protected static void sendJsonResponse(HttpServletResponse response, Object responseObject) throws IOException {
        String json = objectMapper.writeValueAsString(responseObject);
        response.setContentType("application/json");
        PrintWriter out = response.getWriter();
        out.print(json);
        out.flush();
    }

    // 读取请求体并反序列化为指定类型的对象
    protected <T> T readRequestBody(HttpServletRequest request, Class<T> valueType) throws IOException {
        BufferedReader reader = request.getReader();
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }
        String requestBody = sb.toString();
        if (!requestBody.isEmpty()) {
            return objectMapper.readValue(requestBody, valueType);
        } else {
            return null;
        }
    }

    // 获取请求中的查询参数
    private Map<String, String> getQueryParams(HttpServletRequest request) {
        Map<String, String> queryParams = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            queryParams.put(entry.getKey(), entry.getValue()[0]); // 只取第一个值
        }
        return queryParams;
    }
}
